#include <stdint.h>
#include <string.h>

/* HAL */
#include "app_timer.h"
#include "boards.h"
#include "nrf_serial.h"
#include "simple_hal.h"

/* Core */
#include "access_config.h"
#include "access_reliable.h"
#include "device_state_manager.h"
#include "mesh_stack.h"
#include "nrf_mesh.h"
#include "nrf_mesh_config_core.h"
#include "nrf_mesh_configure.h"
#include "nrf_mesh_gatt.h"

/* Provisioning and configuration */
#include "mesh_app_utils.h"
#include "mesh_provisionee.h"

/* Models */
#include "command_client.h"

/* Logging and RTT */
#include "log.h"
#include "rtt_input.h"

/* Example specific includes */
#include "app_config.h"
#include "ble_softdevice_support.h"
#include "example_common.h"
#include "light_switch_example_common.h"
#include "nrf_mesh_config_examples.h"

/*****************************************************************************
 * Definitions
 *****************************************************************************/
#define APP_STATE_OFF (0)
#define APP_STATE_ON (1)
#define UART_BUF_LEN 11

#define APP_UNACK_MSG_REPEAT_COUNT (2)

/* Controls if the model instance should force all mesh messages to be segmented messages. */
#define APP_FORCE_SEGMENTATION (false)
/* Controls the MIC size used by the model instance for sending the mesh messages. */
#define APP_MIC_SIZE (NRF_MESH_TRANSMIC_SIZE_SMALL)
/* Delay value used by the OnOff client for sending OnOff Set messages. */
#define APP_ONOFF_DELAY_MS (50)
/* Transition time value used by the OnOff client for sending OnOff Set messages. */
#define APP_ONOFF_TRANSITION_TIME_MS (100)

APP_TIMER_DEF(m_uart_timer);

static void command_client_register_cb(const command_client_t* p_self, uint8_t type, uint16_t src);
static void command_client_status_cb(const command_client_t* p_self, uint8_t* status, uint16_t src);
static void command_client_data_cb(const command_client_t* p_self, uint8_t* status, uint16_t src);
static void uart_process();

static command_client_t m_command_client = {.register_cb = command_client_register_cb,
                                            .status_cb   = command_client_status_cb,
                                            .data_cb     = command_client_data_cb};

// UART config
static void sleep_handler(void)
{
    (void)sd_app_evt_wait();
}

NRF_SERIAL_DRV_UART_CONFIG_DEF(m_uart0_drv_config, 26, 25, 0, 0, NRF_UART_HWFC_ENABLED, NRF_UART_PARITY_EXCLUDED, NRF_UART_BAUDRATE_115200, 7);
NRF_SERIAL_QUEUES_DEF(serial_queues, 32, 32);
NRF_SERIAL_BUFFERS_DEF(serial_buffs, 1, 1);
NRF_SERIAL_CONFIG_DEF(serial_config, NRF_SERIAL_MODE_POLLING, &serial_queues, &serial_buffs, NULL, sleep_handler);
NRF_SERIAL_UART_DEF(m_serial_uart, 0);

static bool m_device_provisioned;

static void command_client_register_cb(const command_client_t* p_self, uint8_t type, uint16_t src)
{
    UNUSED_PARAMETER(p_self);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Device register, type: %u, address: 0x%4X  \n", type, src);

    uint8_t write_buffer[UART_BUF_LEN];
    write_buffer[0] = COMMAND_OPCODE_REGISTER;
    memcpy(&write_buffer[1], &src, 2);
    write_buffer[3] = type;
    LOG_ERROR("App", nrf_serial_write(&m_serial_uart, write_buffer, sizeof(write_buffer), NULL, NRF_SERIAL_MAX_TIMEOUT));
    // LOG_ERROR("App",nrf_serial_flush(&m_serial_uart, 20));
}

static void command_client_status_cb(const command_client_t* p_self, uint8_t* status, uint16_t src)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Set done, address: 0x%4X  \n", src);
    __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Status (raw)", status, sizeof(status));

    uint8_t write_buffer[UART_BUF_LEN] = {0};
    write_buffer[0]                    = COMMAND_OPCODE_STATUS;
    memcpy(&write_buffer[1], &src, 2);
    memcpy(&write_buffer[3], status, COMMAND_DATA_LENGTH);
    LOG_ERROR("App", nrf_serial_write(&m_serial_uart, write_buffer, sizeof(write_buffer), NULL, NRF_SERIAL_MAX_TIMEOUT));
}

static void command_client_data_cb(const command_client_t* p_self, uint8_t* data, uint16_t src)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Get success, address: 0x%4X  \n", src);
    __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Data (raw)", data, sizeof(data));

    uint8_t write_buffer[UART_BUF_LEN] = {0};
    write_buffer[0]                    = COMMAND_OPCODE_DATA;
    memcpy(&write_buffer[1], &src, 2);
    memcpy(&write_buffer[3], data, COMMAND_DATA_LENGTH);
    LOG_ERROR("App", nrf_serial_write(&m_serial_uart, write_buffer, sizeof(write_buffer), NULL, NRF_SERIAL_MAX_TIMEOUT));
}

// 单播地址打印
static void unicast_address_print(void)
{
    dsm_local_unicast_address_t node_address;
    dsm_local_unicast_addresses_get(&node_address);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Node Address: 0x%04x \n", node_address.address_start);
}

// 配网完成回调
static void provisioning_complete_cb(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Successfully provisioned\n");

    unicast_address_print();
    hal_led_blink_stop();
    hal_led_mask_set(HAL_LED_MASK, LED_MASK_STATE_OFF);
    hal_led_blink_ms(HAL_LED_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_PROV);
}

// 重置节点
static void node_reset(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- Node reset  -----\n");
    hal_led_blink_ms(HAL_LED_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_RESET);
    /* This function may return if there are ongoing flash operations. */
    mesh_stack_device_reset();
}

// 配网器事件回调
static void config_server_evt_cb(const config_server_evt_t* p_evt)
{
    // 重置
    if (p_evt->type == CONFIG_SERVER_EVT_NODE_RESET) {
        node_reset();
    }
}

#if NRF_MESH_LOG_ENABLE
static const char m_usage_string[] = "loggin!\n";
#endif

// // 串口处理
// static void uart_handler(void* point)
// {
//     UNUSED_PARAMETER(point);
// }

// 初始化模型
static void models_init_cb(void)
{
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Initializing and adding models\n");

    LOG_ERROR("App", command_client_init(&m_command_client, 0));

    LOG_ERROR("App", access_model_subscription_list_alloc(m_command_client.model_handle));
}

// 初始化mesh
static void mesh_init(void)
{
    mesh_stack_init_params_t init_params = {.core.irq_priority       = NRF_MESH_IRQ_PRIORITY_LOWEST,
                                            .core.lfclksrc           = DEV_BOARD_LF_CLK_CFG,
                                            .core.p_uuid             = NULL,
                                            .models.models_init_cb   = models_init_cb,
                                            .models.config_server_cb = config_server_evt_cb};

    uint32_t status = mesh_stack_init(&init_params, &m_device_provisioned);
    switch (status) {
        case NRF_ERROR_INVALID_DATA:
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Data in the persistent memory was corrupted. Device starts as unprovisioned.\n");
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Reboot device before starting of the provisioning process.\n");
            break;
        case NRF_SUCCESS:
            break;
        default:
            LOG_ERROR("App", status);
    }
}

// 总初始化方法
static void initialize(void)
{
    // 日志模块初始化
    __LOG_INIT(LOG_SRC_APP | LOG_SRC_ACCESS | LOG_SRC_BEARER, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "----- BLE Mesh Light Switch Client Demo -----\n");

    // 定时器初始化
    LOG_ERROR("App", app_timer_init());

    // led初始化
    hal_leds_init();

    // 蓝牙栈初始化
    ble_stack_init();

    // mesh初始化
    mesh_init();

    uint32_t ret;

    // 串口初始化
    ret = nrf_serial_init(&m_serial_uart, &m_uart0_drv_config, &serial_config);
    LOG_ERROR("App", ret);

    // 串口定时器初始化
    LOG_ERROR("App", app_timer_create(&m_uart_timer, APP_TIMER_MODE_SINGLE_SHOT, uart_process));

    // 串口发送测试文字
    // static char tx_message[] = "Hello nrf_serial!\n\r";

    // ret = nrf_serial_write(&m_serial_uart, tx_message, strlen(tx_message), NULL, NRF_SERIAL_MAX_TIMEOUT);
    // LOG_ERROR("App",ret);
}

static void start(void)
{
    // 检测是否配网
    if (!m_device_provisioned) {
        static const uint8_t            static_auth_data[NRF_MESH_KEY_SIZE] = STATIC_AUTH_DATA;
        mesh_provisionee_start_params_t prov_start_params                   = {.p_static_data                       = static_auth_data,
                                                             .prov_sd_ble_opt_set_cb              = NULL,
                                                             .prov_complete_cb                    = provisioning_complete_cb,
                                                             .prov_device_identification_start_cb = NULL,
                                                             .prov_device_identification_stop_cb  = NULL,
                                                             .prov_abort_cb                       = NULL,
                                                             .p_device_uri                        = EX_URI_LS_CLIENT};
        LOG_ERROR("App", mesh_provisionee_prov_start(&prov_start_params));
    }
    else {
        unicast_address_print();
    }

    // 打印UUID
    mesh_app_uuid_print(nrf_mesh_configure_device_uuid_get());

    // 启动mesh栈
    LOG_ERROR("App", mesh_stack_start());

    __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, m_usage_string);

    hal_led_mask_set(HAL_LED_MASK, LED_MASK_STATE_OFF);
    hal_led_blink_ms(HAL_LED_MASK, LED_BLINK_INTERVAL_MS, LED_BLINK_CNT_START);
}

static void uart_process(void* buffer)
{
    uint8_t* command = (uint8_t*)buffer;
    // __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Buffer address on timer 0x%X, 0x%X\n", buffer, command);
    // __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Receive uart command", command, 11);

    uint8_t opc = command[0];

    switch (opc) {
        case COMMAND_OPCODE_FIND:
            LOG_ERROR("App", command_client_find(&m_command_client));
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Push find command\n");
            break;

        case COMMAND_OPCODE_GET: {
            uint16_t object_addr;
            memcpy(&object_addr, &command[1], 2);
            LOG_ERROR("App", command_client_get(&m_command_client, object_addr));
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Push get command to 0x%#X\n", object_addr);
            break;
        }

        case COMMAND_OPCODE_SET: {
            uint16_t object_addr;
            memcpy(&object_addr, &command[1], 2);

            command_msg_set_t msg;
            memcpy(msg.data, &command[3], COMMAND_DATA_LENGTH);

            LOG_ERROR("App", command_client_set(&m_command_client, object_addr, msg));
            __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Push set command to 0x%#X\n", object_addr);
            __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "data: ", msg.data, sizeof(msg.data));

            break;
        }

        default:
            break;
    }
}

int main(void)
{
    initialize();
    start();

    for (;;) {
        uint8_t command_buffer[UART_BUF_LEN];

        uint32_t ret = nrf_serial_read(&m_serial_uart, command_buffer, UART_BUF_LEN, NULL, 10);
        if (ret != NRF_SUCCESS || !command_buffer[0] || !m_device_provisioned) {
            continue;
        }

        __LOG(LOG_SRC_APP, LOG_LEVEL_INFO, "Buffer address 0x%#X\n", &command_buffer);
        __LOG_XB(LOG_SRC_APP, LOG_LEVEL_INFO, "Receive uart command", command_buffer, sizeof(command_buffer));

        LOG_ERROR("App", app_timer_start(m_uart_timer, APP_TIMER_MIN_TIMEOUT_TICKS, (void*)command_buffer));

        // uart_process();
        (void)sd_app_evt_wait();
    }
}
